/**
 * 安全存储工具类
 * 提供加密存储和安全的Token管理功能
 */

import CryptoJS from 'crypto-js'

// 安全存储配置
interface SecureStorageConfig {
  encryptionKey?: string
  tokenExpiryBuffer?: number // Token过期缓冲时间（毫秒）
  maxTokenAge?: number // Token最大存储时间（毫秒）
}

// Token信息接口
interface TokenInfo {
  token: string
  refreshToken: string
  expiresAt: number
  issuedAt: number
  userId: number
}

// 加密存储项接口
interface EncryptedStorageItem {
  data: string
  timestamp: number
  checksum: string
}

class SecureStorage {
  private readonly encryptionKey: string
  private readonly tokenExpiryBuffer: number
  private readonly maxTokenAge: number
  private readonly storagePrefix = 'secure_'

  constructor(config: SecureStorageConfig = {}) {
    // 生成或使用提供的加密密钥
    this.encryptionKey = config.encryptionKey || this.generateEncryptionKey()
    this.tokenExpiryBuffer = config.tokenExpiryBuffer || 5 * 60 * 1000 // 5分钟缓冲
    this.maxTokenAge = config.maxTokenAge || 24 * 60 * 60 * 1000 // 24小时最大存储时间
  }

  /**
   * 生成加密密钥
   */
  private generateEncryptionKey(): string {
    // 基于设备特征生成密钥
    const deviceInfo = [
      navigator.userAgent,
      navigator.language,
      screen.width,
      screen.height,
      new Date().getTimezoneOffset()
    ].join('|')
    
    return CryptoJS.SHA256(deviceInfo + 'reactim_secure_key').toString()
  }

  /**
   * 加密数据
   */
  private encrypt(data: string): string {
    try {
      const encrypted = CryptoJS.AES.encrypt(data, this.encryptionKey).toString()
      return encrypted
    } catch (error) {
      console.error('Encryption failed:', error)
      throw new Error('Failed to encrypt data')
    }
  }

  /**
   * 解密数据
   */
  private decrypt(encryptedData: string): string {
    try {
      const decrypted = CryptoJS.AES.decrypt(encryptedData, this.encryptionKey)
      return decrypted.toString(CryptoJS.enc.Utf8)
    } catch (error) {
      console.error('Decryption failed:', error)
      throw new Error('Failed to decrypt data')
    }
  }

  /**
   * 生成数据校验和
   */
  private generateChecksum(data: string): string {
    return CryptoJS.SHA256(data + this.encryptionKey).toString().substring(0, 16)
  }

  /**
   * 验证数据完整性
   */
  private verifyChecksum(data: string, checksum: string): boolean {
    return this.generateChecksum(data) === checksum
  }

  /**
   * 安全存储数据
   */
  private setSecureItem(key: string, value: any): boolean {
    try {
      const jsonData = JSON.stringify(value)
      const encryptedData = this.encrypt(jsonData)
      const checksum = this.generateChecksum(jsonData)
      
      const storageItem: EncryptedStorageItem = {
        data: encryptedData,
        timestamp: Date.now(),
        checksum
      }

      localStorage.setItem(this.storagePrefix + key, JSON.stringify(storageItem))
      return true
    } catch (error) {
      console.error('Secure storage set failed:', error)
      return false
    }
  }

  /**
   * 安全获取数据
   */
  private getSecureItem<T>(key: string): T | null {
    try {
      const itemStr = localStorage.getItem(this.storagePrefix + key)
      if (!itemStr) return null

      const storageItem: EncryptedStorageItem = JSON.parse(itemStr)
      
      // 检查数据是否过期（超过最大存储时间）
      if (Date.now() - storageItem.timestamp > this.maxTokenAge) {
        this.removeSecureItem(key)
        return null
      }

      const decryptedData = this.decrypt(storageItem.data)
      
      // 验证数据完整性
      if (!this.verifyChecksum(decryptedData, storageItem.checksum)) {
        console.warn('Data integrity check failed for key:', key)
        this.removeSecureItem(key)
        return null
      }

      return JSON.parse(decryptedData) as T
    } catch (error) {
      console.error('Secure storage get failed:', error)
      this.removeSecureItem(key)
      return null
    }
  }

  /**
   * 移除安全存储项
   */
  private removeSecureItem(key: string): boolean {
    try {
      localStorage.removeItem(this.storagePrefix + key)
      return true
    } catch (error) {
      console.error('Secure storage remove failed:', error)
      return false
    }
  }

  /**
   * 存储Token信息
   */
  setTokenInfo(tokenInfo: Omit<TokenInfo, 'issuedAt'>): boolean {
    const fullTokenInfo: TokenInfo = {
      ...tokenInfo,
      issuedAt: Date.now()
    }

    return this.setSecureItem('token_info', fullTokenInfo)
  }

  /**
   * 获取Token信息
   */
  getTokenInfo(): TokenInfo | null {
    return this.getSecureItem<TokenInfo>('token_info')
  }

  /**
   * 获取访问Token
   */
  getAccessToken(): string | null {
    const tokenInfo = this.getTokenInfo()
    if (!tokenInfo) return null

    // 检查Token是否即将过期
    if (this.isTokenExpiringSoon(tokenInfo)) {
      return null
    }

    return tokenInfo.token
  }

  /**
   * 获取刷新Token
   */
  getRefreshToken(): string | null {
    const tokenInfo = this.getTokenInfo()
    return tokenInfo?.refreshToken || null
  }

  /**
   * 检查Token是否即将过期
   */
  isTokenExpiringSoon(tokenInfo?: TokenInfo): boolean {
    const info = tokenInfo || this.getTokenInfo()
    if (!info) return true

    const now = Date.now()
    const expiryTime = info.expiresAt - this.tokenExpiryBuffer
    
    return now >= expiryTime
  }

  /**
   * 检查Token是否已过期
   */
  isTokenExpired(tokenInfo?: TokenInfo): boolean {
    const info = tokenInfo || this.getTokenInfo()
    if (!info) return true

    return Date.now() >= info.expiresAt
  }

  /**
   * 更新Token
   */
  updateTokens(token: string, refreshToken: string, expiresIn: number): boolean {
    const tokenInfo = this.getTokenInfo()
    if (!tokenInfo) {
      console.error('Cannot update tokens: no existing token info')
      return false
    }

    const updatedTokenInfo: TokenInfo = {
      ...tokenInfo,
      token,
      refreshToken,
      expiresAt: Date.now() + (expiresIn * 1000),
      issuedAt: Date.now()
    }

    return this.setTokenInfo(updatedTokenInfo)
  }

  /**
   * 清除所有Token信息
   */
  clearTokens(): boolean {
    return this.removeSecureItem('token_info')
  }

  /**
   * 存储敏感用户数据
   */
  setSecureUserData(key: string, data: any): boolean {
    return this.setSecureItem(`user_${key}`, data)
  }

  /**
   * 获取敏感用户数据
   */
  getSecureUserData<T>(key: string): T | null {
    return this.getSecureItem<T>(`user_${key}`)
  }

  /**
   * 移除敏感用户数据
   */
  removeSecureUserData(key: string): boolean {
    return this.removeSecureItem(`user_${key}`)
  }

  /**
   * 清除所有安全存储数据
   */
  clearAllSecureData(): boolean {
    try {
      const keys = Object.keys(localStorage).filter(key => 
        key.startsWith(this.storagePrefix)
      )
      
      keys.forEach(key => localStorage.removeItem(key))
      return true
    } catch (error) {
      console.error('Clear all secure data failed:', error)
      return false
    }
  }

  /**
   * 验证存储完整性
   */
  validateStorageIntegrity(): boolean {
    try {
      const tokenInfo = this.getTokenInfo()
      return tokenInfo !== null
    } catch (error) {
      console.error('Storage integrity validation failed:', error)
      return false
    }
  }

  /**
   * 获取存储统计信息
   */
  getStorageStats(): {
    itemCount: number
    totalSize: number
    oldestItem: number | null
    newestItem: number | null
  } {
    const keys = Object.keys(localStorage).filter(key => 
      key.startsWith(this.storagePrefix)
    )

    let totalSize = 0
    let oldestTimestamp: number | null = null
    let newestTimestamp: number | null = null

    keys.forEach(key => {
      const itemStr = localStorage.getItem(key)
      if (itemStr) {
        totalSize += itemStr.length
        
        try {
          const storageItem: EncryptedStorageItem = JSON.parse(itemStr)
          if (oldestTimestamp === null || storageItem.timestamp < oldestTimestamp) {
            oldestTimestamp = storageItem.timestamp
          }
          if (newestTimestamp === null || storageItem.timestamp > newestTimestamp) {
            newestTimestamp = storageItem.timestamp
          }
        } catch (error) {
          // 忽略解析错误的项
        }
      }
    })

    return {
      itemCount: keys.length,
      totalSize,
      oldestItem: oldestTimestamp,
      newestItem: newestTimestamp
    }
  }
}

// 创建默认实例
export const secureStorage = new SecureStorage()

// 导出类型
export type { TokenInfo, SecureStorageConfig }